Skip to content

Fix zero-repetition measurement record shapes in simulator - #8316

Open
Prahalad-ship-it wants to merge 2 commits into
quantumlib:mainfrom
Prahalad-ship-it:practice-fix
Open

Fix zero-repetition measurement record shapes in simulator#8316
Prahalad-ship-it wants to merge 2 commits into
quantumlib:mainfrom
Prahalad-ship-it:practice-fix

Conversation

@Prahalad-ship-it

Copy link
Copy Markdown

Summary

This PR fixes an issue in Cirq’s sampling interface where the simulator returned incorrectly shaped empty measurement records when circuits were run with repetitions=0.

Previously, the zero-repetition path bypassed execution but hardcoded an empty record shape of (0, 1, 1). This occurred regardless of how many qubits were measured or how many times a key was repeated.

This change updates the zero-repetition path so that Result.records accurately preserves the circuit's structural dimensions:
(repetitions, measurement_instances, measured_qubits) -> (0, measurement_instances, measured_qubits)


Problem

Cirq’s SimulatesSamples.run_sweep_iter method includes a fast path for zero repetitions to avoid unnecessary simulation. However, it still must construct a valid ResultDict containing accurately dimensioned empty measurement records.

Before this change, the implementation initialized these records using np.empty([0, 1, 1]). This fallback shape failed to represent circuits utilizing multi-qubit measurement operations or repeated measurement keys.

Minimal Reproducible Example

import cirq

q0, q1 = cirq.LineQubit.range(2)

circuit = cirq.Circuit(
    cirq.measure(q0, q1, key="m"),
    cirq.measure(q0, q1, key="m"),
)

result = cirq.Simulator().run(circuit, repetitions=0)

Previous Behavior

result.records["m"].shape
# Output: (0, 1, 1) -> Incorrect: key "m" occurs twice, measuring 2 qubits each time.

Corrected Behavior

result.records["m"].shape
# Output: (0, 2, 2)
Dimension Value Meaning
Repetitions 0 No samples were requested
Measurement instances 2 The key "m" occurs twice in the circuit
Measured qubits 2 Each measurement operation acts on 2 qubits (q0, q1)

Note: This is a correctness fix, not a performance optimization. No unverified simulator optimizations have been introduced.


Tests Added

Added a dedicated regression test in simulator_test.py that constructs a circuit containing multiple qubits and repeated measurement keys. The test runs with repetitions=0 and asserts:

assert result.repetitions == 0
assert result.records["m"].shape == (0, 2, 2)

Prior to this fix, the shape assertion would fail with a layout mismatch.


Validation Performed

The following checks passed locally:

  • Linting: ruff checks passed successfully on all modified files.
  • Compilation: Python compilation validated for cirq-core/cirq/sim.
  • Test Suite Execution:
    • Passed 46 targeted simulator and sampler tests.
    • Passed 474 simulator, sparse-simulator, and density-matrix-simulator tests.
    • Passed 73 sampler, zero-sampler, and Clifford-simulator tests.
    • Passed 641 comprehensive backend tests during broad directory auditing.

Files Changed

cirq-core/cirq/sim/simulator.py

Updated the zero-repetition execution pipeline to:

  • Count unique measurement instances per key.
  • Extract and preserve the explicit measured-qubit width.
  • Allocate matching empty NumPy arrays matching actual structural layouts.
  • Raise a clear error if mismatched measurement widths are associated with an identical key.

cirq-core/cirq/sim/simulator_test.py

Added regression coverage validating repeated multi-qubit measurement outputs under zero repetitions.


API Compatibility

This change is fully backwards-compatible.

  • Public type signatures, classes, imports, serialization formats, and standard positive-repetition outputs remain entirely unchanged.
  • The only observable behavioral modification is that edge-case empty measurement arrays now report accurate matrix dimensions.

@Prahalad-ship-it
Prahalad-ship-it requested a review from a team as a code owner September 9, 2026 21:00
@google-cla

google-cla Bot commented Sep 9, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@github-actions github-actions Bot added the size: S 10< lines changed <50 label Sep 9, 2026

@arettig arettig left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for doing this! I have a recommendation to simplify this code, see below.

Comment on lines 89 to +102
for _, op, _ in program.findall_operations_with_gate_type(ops.MeasurementGate):
records[protocols.measurement_key_name(op)] = np.empty([0, 1, 1])
key = protocols.measurement_key_name(op)
qid_shape = protocols.qid_shape(op)
if key in record_shapes:
num_instances, expected_qid_shape = record_shapes[key]
if qid_shape != expected_qid_shape:
raise ValueError(
'Different qid shapes for repeated measurement: '
f'key={key!r}, prev_qid_shape={expected_qid_shape}, '
f'qid_shape={qid_shape}'
)
record_shapes[key] = (num_instances + 1, qid_shape)
else:
record_shapes[key] = (1, qid_shape)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should just call _get_measurement_shapes here from the Sampler parent class, as is done in zeros_sampler.py.

result = cirq.Simulator().run(circuit, repetitions=0)

assert result.repetitions == 0
assert result.records['m'].shape == (0, 2, 2)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a test case where to number of measurements is different than the number of qubits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size: S 10< lines changed <50

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants